#ifndef BASE_MAP_H
#define BASE_MAP_H

#include "base_core.h"

#include "base_array.h"
#include "base_memory.h"


//-----------------------------------------------------------------------------
// Associative array
//-----------------------------------------------------------------------------


/**
 * \brief Key-value (string -> pointer) pair structure
 */
typedef struct
{
    /// \brief Key of the pair
    char *key;

    /// \brief Value of the pair
    void *data;

} MapPair;

/**
 * \brief Associative array.
 */
typedef struct
{
    MapPair *data;
} Map;

/**
 * \brief Create a new map.
 * \return An empty map.
 */
Map* map_new(void);

/**
 * \brief Free a map.
 * \param map Map to free
 */
void map_delete(Map *map);

/**
 * \brief Insert a key-value pair in the map.
 * \param map Map
 * \param key Key of the pair
 * \param data Data of the pair
 * \return 0 on success, -1 if the key was already present in the map.
 */
int map_insert(Map *map, const char *key, void *data);

/**
 * \brief Remove a key-value pair from the map.
 * \param map Map
 * \param key Key to remove
 * \return 0 on success, -1 if the key wasn't present in the map.
 */
int map_remove(Map *map, const char *key);

/**
 * \brief Lookup a value from the map.
 * \param map Map
 * \param key Key to lookup
 * \return Data, or 0 if the key wasn't present in the map.
 */
void* map_lookup(Map *map, const char *key);

/**
 * \brief Get number of elements in the map.
 * \param map Map
 * \return Number of elements in the map.
 */
int map_size(Map *map);

/**
 * \brief Function to iterate in a map.
 * \param map Map
 * \param i Previous element from the iteration
 * \return First element in the map if called with 0, next element in the map, or 0 if last element in the map.
 * \warning Do not modify the map while iterating.
 */
MapPair* map_iterator(Map *map, MapPair *i);

/**
 * \brief Macro helper to iterate inside a map.
 */
#define MAP_ITERATE(map, i) for(MapPair *i = map_iterator(map, 0); i; i = map_iterator(map, i))

/**
 * \brief Macro helper to remove all pairs from a map, with optional operations before.
 */
#define MAP_ERASE(map, i) for(MapPair *i = map_iterator(map, 0); i; map_remove(map, i->key), i = map_iterator(map, 0))

#endif
